package com.jin.webvideo.base.util;


import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ObjectPool<T> {
    private int size;
    private int current;
    private Queue<T> queue;
    private ReentrantLock lock;
    private Condition condition;
    private ObjectInitializer<T> initializer;
    public ObjectPool(int size, ObjectInitializer<T> initializer) {
        this.size = size;
        this.current = 0;
        this.queue = new LinkedList<T>();
        this.lock = new ReentrantLock();
        this.condition = this.lock.newCondition();
        this.initializer = initializer;
    }

    public T get() throws InterruptedException {
        lock.lock();
        // 不存在可用对象 且创建的对象已达到阈值
        while (queue.isEmpty() && current >= size) {
            // 线程等待
            condition.await();
        }
        T first = null;
        // 存在可重用对象
        if (!queue.isEmpty()) {
            first = queue.poll();
            initializer.initialize(first);
        }

        // 未达到最大值
        else if (current < size) {
            first = initializer.create(this);
            current ++;
        }
        lock.unlock();
        return first;
    }

    /**
     * 超过最大值不再等待而是，直接新建返回
     * @return
     */
    public T getOrCreate() {
        lock.lock();
        while (queue.isEmpty() && current >= size) {
            return initializer.create(this);
        }
        T first = null;
        // 存在可重用对象
        if (!queue.isEmpty()) {
            first = queue.poll();
            initializer.initialize(first);
        }

        // 未达到最大值
        else if (current < size) {
            first = initializer.create(this);
            current ++;
        }
        lock.unlock();
        return first;
    }

    public boolean recycle(T obj) {
        if (queue.size() >= size) {
            return false;
        }
        lock.lock();
        boolean r = queue.offer(obj);
        condition.signal();
        lock.unlock();
        return r;
    }
}
